const tf = require('@tensorflow/tfjs-node')

// 假设这是100期历史开奖数据
const historicalData = [
  { time: '2022-01-01', number: 22 },
  { time: '2022-01-02', number: 21 },
  { time: '2022-01-03', number: 23 },
  { time: '2022-01-04', number: 24 },
  { time: '2022-01-05', number: 25 },
  { time: '2022-01-06', number: 26 },
  { time: '2022-01-07', number: 27 },
  { time: '2022-01-08', number: 28 },
  { time: '2022-01-09', number: 29 },
  { time: '2022-01-10', number: 30 }
  // 假设此处有100期历史数据
]

// 数据归一化：将号码映射到 [0, 1] 范围
const normalizeData = (number) => {
  return (number - 1) / 48 // 1-49 范围映射到 0-1
}

// 准备训练数据：使用过去10期数据预测下一期
const prepareData = (historicalData) => {
  const inputData = [] // 存储输入数据
  const outputData = [] // 存储目标输出数据

  // 从第10期开始，每次取过去10期数据作为输入，下一期数据作为输出
  for (let i = 10; i < historicalData.length; i++) {
    // 使用过去10期的号码作为输入
    const input = historicalData.slice(i - 10, i).map((item) => normalizeData(item.number))

    // 下一期的号码作为目标
    const output = normalizeData(historicalData[i].number)

    inputData.push(input) // 将输入数据添加到数组中
    outputData.push(output) // 将输出数据添加到数组中
  }

  return { inputData, outputData } // 返回训练数据
}

// 准备训练数据
const { inputData, outputData } = prepareData(historicalData)

// 将数据转换为 Tensor 格式
const inputTensor = tf.tensor2d(inputData, [inputData.length, 10]) // 明确指定形状
const outputTensor = tf.tensor2d(outputData, [outputData.length, 1])

// 构建模型
const model = tf.sequential() // 创建一个顺序模型（每一层都是顺序的）
model.add(tf.layers.dense({ units: 64, activation: 'relu', inputShape: [10] })) // 添加一个全连接层，包含 64 个神经元，激活函数使用 ReLU，输入数据维度为 10
model.add(tf.layers.dense({ units: 1, activation: 'linear' })) // 添加一个全连接层，输出维度为 1，激活函数使用线性函数

// 编译模型
model.compile({ optimizer: 'adam', loss: 'meanSquaredError' })

// 训练模型
async function trainModel() {
  console.log('Training data shape: ', inputTensor.shape)
  console.log('Output data shape: ', outputTensor.shape)

  await model.fit(inputTensor, outputTensor, {
    epochs: 100, // 设置训练轮数为100
    verbose: 0, // 禁用进度条显示
    callbacks: {
      onEpochEnd: (epoch, logs) => {
        console.log(`Epoch ${epoch + 1}: loss = ${logs.loss}`)
      },
      onBatchEnd: (batch, logs) => {
        console.log(`Batch ${batch + 1}: loss = ${logs.loss}`)
      }
    }
  })
  console.log('模型训练完成') // 训练完成后输出提示信息
}

// 预测下一期号码
async function predictNextNumber(inputData) {
  if (inputData.length !== 10) {
    throw new Error('Input data must contain 10 values')
  }

  const inputTensor = tf.tensor2d([inputData], [1, 10]) // 确保是二维输入
  const prediction = model.predict(inputTensor) // 进行预测
  const predictionArray = prediction.arraySync() // 将预测结果转换为 JavaScript 数组

  // 将归一化的预测结果转回 [1, 49] 范围
  let predictedNumber = Math.round(predictionArray[0][0] * 48) + 1

  // 确保预测值在 [1, 49] 范围内
  predictedNumber = Math.min(49, Math.max(1, predictedNumber))

  return predictedNumber // 返回预测的号码
}

// 主函数
async function main() {
  // 训练模型
  await trainModel()

  // 从历史数据中提取最后10期数据进行预测
  const last10Data = historicalData.slice(-10).map((item) => normalizeData(item.number))

  console.log('Last 10 data: ', last10Data)

  let predictedNumbers = [] // 存储预测的24期号码
  for (let i = 0; i < 24; i++) {
    // 预测下一期的号码
    const nextNumber = await predictNextNumber(last10Data)
    predictedNumbers.push(nextNumber)

    // 将预测的号码添加到数据中，作为下一轮预测的输入
    last10Data.push(normalizeData(nextNumber))
    last10Data.shift() // 保持输入数据的长度为10
  }

  console.log('预测的24期号码：', predictedNumbers) // 输出预测的24期号码
}

// 调用主函数
main()
